package icu.shaoyayu.common.utll.encryption;


import icu.shaoyayu.common.utll.exception.CustomException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * @author shaoyayu
 * @date 2021/12/22
 * @apiNote
 */
public class AesCbcEncryption {
    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("Message: " + message);
        String key = "123456";
        String encrypt = encrypt(key, message);
        System.out.println("加密后数据:"+encrypt);
        String decrypt = decrypt(key, encrypt);
        System.out.println("解密后:"+decrypt);
    }

    /**
     * 加密字符串
     * @param key
     * @param originalText
     * @return
     */
    public static String encrypt(String key,String originalText){
        try {
            byte[] keys = testKey(key);
            byte[] encrypt = encrypt(keys, originalText.getBytes(StandardCharsets.UTF_8));
            return  Base64.getEncoder().encodeToString(encrypt);
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("encryption exception："+e.getMessage());
        }
    }

    public static String decrypt(String key,String ciphertext){
        try {
            byte[] keys = testKey(key);
            byte[] encode = Base64.getDecoder().decode(ciphertext);
            byte[] encrypt = decrypt(keys, encode);
            return new String(encrypt,StandardCharsets.UTF_8);
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("decrypt exception："+e.getMessage());
        }
    }

    /**
     * 加密字节
     * @param key
     * @param input
     * @return
     * @throws GeneralSecurityException
     */
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        // CBC模式需要生成一个16 bytes的initialization vector:
        SecureRandom sr = SecureRandom.getInstanceStrong();
        byte[] iv = sr.generateSeed(16);
        IvParameterSpec ivps = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps);
        byte[] data = cipher.doFinal(input);
        // IV不需要保密，把IV和密文一起返回:
        return join(iv, data);
    }

    /**
     * 解密字节
     * @param key
     * @param input
     * @return
     * @throws GeneralSecurityException
     */
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 把input分割成IV和密文:
        byte[] iv = new byte[16];
        byte[] data = new byte[input.length - 16];
        System.arraycopy(input, 0, iv, 0, 16);
        System.arraycopy(input, 16, data, 0, data.length);
        // 解密:
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivps = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);
        return cipher.doFinal(data);
    }

    public static byte[] join(byte[] bs1, byte[] bs2) {
        byte[] r = new byte[bs1.length + bs2.length];
        System.arraycopy(bs1, 0, r, 0, bs1.length);
        System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
        return r;
    }

    /**
     * 保存秘钥的16位
     * @param key
     * @return
     */
    private static byte[] testKey(String key){
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 16; i++) {
            // 如果key的长度大于16位，删除后面的
            // 如果小于16位，自动在后面补齐 0
            if (i<key.length()-1){
                stringBuilder.append(key.toCharArray()[i]);
            }else {
                stringBuilder.append("0");
            }
        }
        return stringBuilder.toString().getBytes();
    }

}
